package darknet.application.chat.impl;

import darknet.application.chat.impl.net.ChatMessageFactory;
import darknet.application.chat.spec.Session;
import darknet.application.chat.spec.SessionObserver;
import darknet.application.chat.impl.net.message.PrivateMessage;
import darknet.application.chat.impl.net.message.SessionExitMessage;
import darknet.core.spec.net.NetworkManager;
import darknet.core.spec.net.Node;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Session implementation
 *
 * @author yoyo
 */
public class SessionImpl implements Session {
    
    /** NetworkManager */
    private NetworkManager network;

    /** Chat message factory */
    private ChatMessageFactory factory;
    
    /** Chat with this node */
    private Node chatWithMe;

    /** Observers */
    private Set<SessionObserver> observers;

    /** Flag start ? Y/N */
    private boolean isStarted;

    /** Flag node has exit ? Y/N */
    private boolean nodeIsExit;

    /**
     * Initialise a new Session Impl.
     *
     * @param network
     * @param chatWithMe
     */
    public SessionImpl(NetworkManager network, Node chatWithMe) {

        if (network == null) {
            throw new IllegalArgumentException("network is null");
        }
        this.network = network;

        if (chatWithMe == null) {
            throw new IllegalArgumentException("chatWithMe is null");
        }
        this.chatWithMe = chatWithMe;

        factory = ChatMessageFactory.getInstance(network);
        observers = new HashSet<SessionObserver>(1);
    }

    public SessionImpl(NetworkManager network, Node chatWithMe,
            boolean started) {
        this(network, chatWithMe);
        isStarted = true;
    }

    @Override
    public synchronized void start() throws IOException {
        if (isStarted) {
            return;
        }
        isStarted = true;
        network.send(factory.makeSessionStartMessage(chatWithMe));
    }

    @Override
    public void speak(String message) throws IOException {

        if (nodeIsExit) {
            start();
        }

        network.send(factory.makePrivateMessage(message, chatWithMe));
    }

    @Override
    public void exit() throws IOException {
        network.send(factory.makeSessionExitMessage(chatWithMe));
    }

    @Override
    public Node getNode() {
        return chatWithMe;
    }

    @Override
    public void addSessionObserver(SessionObserver toAdd) {
        if (toAdd == null) {
            throw new IllegalArgumentException("toAdd is null");
        }
        observers.add(toAdd);
    }

    @Override
    public void removeSessionObserver(SessionObserver toRemove) {
        if (toRemove == null) {
            throw new IllegalArgumentException("toRemove is null");
        }
        observers.remove(toRemove);
    }

    @Override
    public List<SessionObserver> getSessionObservers() {
        return new ArrayList<SessionObserver>(observers);
    }

    /**
     * Broadcast the new private message
     * @param message
     */
    void newPrivateMessage(PrivateMessage message) {

       for (SessionObserver observer : observers) {
            observer.newPrivateMessage(message);
        }
    }

    /**
     * Broadvast the new exit message.
     * @param message
     */
    void newExitSessionMessage(SessionExitMessage message) {
        
        nodeIsExit = true;

        for (SessionObserver observer : observers) {
            observer.newExitSessionMessage(message);
        }
    }
}
